﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Controls;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Input;
using System.Windows;
using System.Windows.Threading;
using WInSPen.BaseClass;
using WinSPen.Controls;
using WinSPen.Settings;
using WinSPen.BaseClass;

namespace WinSPen.ViewModels
{
    public class WSPTextBoxViewModel : ViewModelBase
    {
        private Visibility _topButtonVisibility = Visibility.Collapsed;

        public Visibility TopButtonVisibility
        {
            get { return _topButtonVisibility; }
            set { _topButtonVisibility = value; OnPropertyChanged("TopButtonVisibility"); }
        }

        private Visibility _bottomButtonVisibility = Visibility.Collapsed;

        public Visibility BottomButtonVisibility
        {
            get { return _bottomButtonVisibility; }
            set { _bottomButtonVisibility = value; OnPropertyChanged("BottomButtonVisibility"); }
        }

        private RelayCommand _cmdRemoveTextBox;

        public RelayCommand CmdRemoveTextBox
        {
            get
            {
                if (_cmdRemoveTextBox == null)
                {
                    _cmdRemoveTextBox = new RelayCommand(param => RemoveTextBox());
                }
                return _cmdRemoveTextBox;
            }
        }

        private void RemoveTextBox()
        {
            InkCanvas parentCanvas = TryFindParent<InkCanvas>(this._view);

            if (parentCanvas != null)
            {
                // 텍스트 박스 삭제
                parentCanvas.Children.Remove(this._view);
            }
        }

        private WSPTextBox _view;

        public WSPTextBoxViewModel(Control ctrl)
        {
            this._view = ctrl as WSPTextBox;
            
            this._view.MouseEnter += new MouseEventHandler(View_MouseEnter);
            this._view.MouseLeave += new MouseEventHandler(View_MouseLeave);
            this._view.SizeChanged += new SizeChangedEventHandler(View_SizeChanged);
            this._view.InnerTextBox.TextChanged += new TextChangedEventHandler(InnerTextBox_TextChanged);
            this._view.InnerTextBox.GotFocus += new RoutedEventHandler(InnerTextBox_GotFocus);
            this._view.InnerTextBox.LostFocus += new RoutedEventHandler(InnerTextBox_LostFocus);
            this._view.InnerTextBox.KeyDown += new KeyEventHandler(InnerTextBox_KeyDown);

            this._view.UpdateLayout();
            this._view.InnerTextBox.Focus();
        }

        void InnerTextBox_KeyDown(object sender, KeyEventArgs e)
        {
            // ESC를 누르면 텍스트 입력이 종료되도록 함
            if (e.Key == Key.Escape)
            {
                InkCanvas parentCanvas = TryFindParent<InkCanvas>(this._view);

                if (parentCanvas != null)
                {
                    parentCanvas.Focus();
                }
            }
        }

        private void InnerTextBox_LostFocus(object sender, RoutedEventArgs e)
        {
            TextBox textbox = sender as TextBox;
            InkCanvas parentCanvas = TryFindParent<InkCanvas>(textbox);

            textbox.BorderThickness = new Thickness(0);

            // 삭제 버튼을 없애야 한다.
            if (TopButtonVisibility == Visibility.Visible)
            {
                // 이 부분이 없으면 포커스가 버튼으로 넘어가는 순간에 버튼의 command가 실행되지 않음
                if (this._view.TopRemoveButton.IsMouseOver == false)
                {
                    TopButtonVisibility = Visibility.Collapsed;
                }
            }
            else if (BottomButtonVisibility == Visibility.Visible)
            {
                // 이 부분이 없으면 포커스가 버튼으로 넘어가는 순간에 버튼의 command가 실행되지 않음
                if (this._view.BottomRemoveButton.IsMouseOver == false)
                {
                    BottomButtonVisibility = Visibility.Collapsed;
                }
            }

            if (textbox.Text.Length <= 0)
            {
                if (_isTextBoxResizing == false)
                {
                    parentCanvas.Children.Remove(this._view);
                }
            }
        }

        private void InnerTextBox_GotFocus(object sender, RoutedEventArgs e)
        {
            // 삭제 버튼 생성

            TextBox textbox = sender as TextBox;
            InkCanvas parentCanvas = TryFindParent<InkCanvas>(textbox);

            textbox.BorderThickness = new Thickness(1);

            // 지우기 버튼 visibility 변화
            if (parentCanvas != null)
            {
                if ((double)this._view.GetValue(InkCanvas.TopProperty) > parentCanvas.ActualHeight / 2)
                {
                    TopButtonVisibility = Visibility.Visible;
                }
                else
                {
                    BottomButtonVisibility = Visibility.Visible;
                }
            }
        }

        private void View_SizeChanged(object sender, SizeChangedEventArgs e)
        {
            // 사이즈가 변경된 경우 줄이 늘어나면 사이즈 증가
            WSPTextBox wspTextBox = sender as WSPTextBox;
            InkCanvas parentCanvas = TryFindParent<InkCanvas>(wspTextBox);
            double minHeight = wspTextBox.InnerTextBox.LineCount * wspTextBox.InnerTextBox.FontSize * 1.33 + 20;
            double maxHeight = parentCanvas.ActualHeight - (double)wspTextBox.GetValue(InkCanvas.TopProperty);

            // 너비가 줄어서 텍스트 줄이 늘어남으로 인해 높이가 높아지는 경우
            if (e.NewSize.Width < e.PreviousSize.Width)
            {
                if (wspTextBox.Height > maxHeight)
                {
                    wspTextBox.Width = e.PreviousSize.Width;
                    wspTextBox.Height = maxHeight;
                }
            }

            // 높이는 텍스트가 표시되는 최소줄보다 작아질 수는 없음
            if (wspTextBox.Height < minHeight)
            {
                wspTextBox.Height = minHeight;
            }
        }

        private void InnerTextBox_TextChanged(object sender, TextChangedEventArgs e)
        {
            // 줄이 늘어나는 경우 사이즈 증가
            TextBox textbox = sender as TextBox;
            WSPTextBox wspTextBox = TryFindParent<UserControl>(textbox) as WSPTextBox;
            double minHeight = textbox.LineCount * textbox.FontSize * 1.33 + 20;

            if (wspTextBox.Height < minHeight)
            {
                wspTextBox.Height = minHeight;
            }
        }

        private void View_MouseLeave(object sender, MouseEventArgs e)
        {
            // Text Mode에서만 동작
            if (ModeSetting.GetInstance().DrawMode != DrawingMode.TextMode)
            {
                return;
            }

            WSPTextBox wspTextBox = sender as WSPTextBox;

            // 모든 resizing border에 적용
            foreach (Border item in (wspTextBox.DataContext as WSPTextBoxViewModel).GetResizeBorderList())
            {
                item.BorderBrush = new SolidColorBrush(Colors.Transparent);
                item.Background = new SolidColorBrush(Colors.Transparent);
                item.MouseLeftButtonDown -= ResizeBorder_MouseLeftButtonDown;
                item.MouseMove -= ResizeBorder_MouseMove;
                item.MouseLeftButtonUp -= ResizeBorder_MouseLeftButtonUp;
            }
        }

        private void View_MouseEnter(object sender, MouseEventArgs e)
        {
            // Text Mode에서만 동작
            if (ModeSetting.GetInstance().DrawMode != DrawingMode.TextMode)
            {
                return;
            }

            WSPTextBox WSPTextBox = sender as WSPTextBox;

            // 8개의 크기변경용 Border에 모두 적용
            foreach (Border item in (WSPTextBox.DataContext as WSPTextBoxViewModel).GetResizeBorderList())
            {
                item.BorderBrush = new SolidColorBrush(Colors.Gray);
                item.Background = new SolidColorBrush(Colors.White);
                item.MouseLeftButtonDown += new MouseButtonEventHandler(ResizeBorder_MouseLeftButtonDown);
                item.MouseMove += new MouseEventHandler(ResizeBorder_MouseMove);
                item.MouseLeftButtonUp += new MouseButtonEventHandler(ResizeBorder_MouseLeftButtonUp);
            }
        }

        private bool _isTextBoxResizing = false;
        private Border _selectedResizingBorder;
        private double _currentPositionX;
        private double _currentPositionY;

        private void ResizeBorder_MouseMove(object sender, MouseEventArgs e)
        {
            // Text Mode에서만 작동
            if (ModeSetting.GetInstance().DrawMode != DrawingMode.TextMode)
            {
                return;
            }

            // Left button이 눌려진 상태에서만 작동
            if (e.LeftButton == MouseButtonState.Released)
            {
                return;
            }

            // Resizing border를 마우스로 잡아놓은 상태에서만 진행
            if (this._isTextBoxResizing == true)
            {
                InkCanvas parentCanvas = TryFindParent<InkCanvas>(this._view);
                double newX = Mouse.GetPosition(parentCanvas).X;
                double newY = Mouse.GetPosition(parentCanvas).Y;
                double maxWidth = parentCanvas.ActualWidth - 10;
                double maxHeight = parentCanvas.ActualHeight - 10;
                double minHeight = this._view.InnerTextBox.LineCount * this._view.InnerTextBox.FontSize * 1.33 + 20;

                if (this._selectedResizingBorder == this._view.ResizeBorder3)
                {
                    // 좌우 사이즈만 변경
                    if (this._view.ActualWidth + newX - this._currentPositionX > 34 &&
                        newX < maxWidth)
                    {
                        this._view.Width += newX - this._currentPositionX;
                        this._currentPositionX = newX;
                    }
                }
                else if (this._selectedResizingBorder == this._view.ResizeBorder9)
                {
                    // 좌우 위치이동 & 좌우 사이즈 변경
                    if (this._view.ActualWidth - (newX - this._currentPositionX) > 34 &&
                        newX > 0)
                    {
                        this._view.SetValue(InkCanvas.LeftProperty, newX);
                        this._view.Width -= newX - this._currentPositionX;
                        this._currentPositionX = newX;
                    }
                }
                else if (this._selectedResizingBorder == this._view.ResizeBorder12)
                {
                    // 상하이동 & 상하 사이즈 변경
                    if (this._view.ActualHeight - (newY - this._currentPositionY) > minHeight &&
                        newY > 0)
                    {
                        this._view.SetValue(InkCanvas.TopProperty, newY);
                        this._view.Height -= newY - this._currentPositionY;
                        this._currentPositionY = newY;
                    }
                }
                else if (this._selectedResizingBorder == this._view.ResizeBorder6)
                {
                    // 상하 사이즈만 변경
                    if (this._view.ActualHeight + newY - this._currentPositionY > minHeight &&
                        newY < maxHeight)
                    {
                        this._view.Height += newY - this._currentPositionY;
                        this._currentPositionY = newY;
                    }
                }
                else if (this._selectedResizingBorder == this._view.ResizeBorder2)
                {
                    // 상하 이동 & 좌우 사이즈 변경
                    if (this._view.ActualWidth + newX - this._currentPositionX > 34 &&
                        newX < maxWidth)
                    {
                        this._view.Width += newX - this._currentPositionX;
                        this._currentPositionX = newX;
                    }
                    if (this._view.ActualHeight - (newY - this._currentPositionY) > minHeight &&
                        newY > 0)
                    {
                        this._view.SetValue(InkCanvas.TopProperty, newY);
                        this._view.Height -= newY - this._currentPositionY;
                        this._currentPositionY = newY;
                    }
                }
                else if (this._selectedResizingBorder == this._view.ResizeBorder8)
                {
                    // 좌우 이동 & 상하 사이즈 변경
                    if (this._view.ActualWidth - (newX - this._currentPositionX) > 34 &&
                        newX > 0)
                    {
                        this._view.SetValue(InkCanvas.LeftProperty, newX);
                        this._view.Width -= newX - this._currentPositionX;
                        this._currentPositionX = newX;
                    }
                    if (this._view.ActualHeight + newY - this._currentPositionY > minHeight &&
                        newY < maxHeight)
                    {
                        this._view.Height += newY - this._currentPositionY;
                        this._currentPositionY = newY;
                    }
                }
                else if (this._selectedResizingBorder == this._view.ResizeBorder10)
                {
                    // 상하좌우 이동 & 상하좌우 사이즈 변경
                    if (this._view.ActualWidth - (newX - this._currentPositionX) > 34 &&
                        newX > 0)
                    {
                        this._view.SetValue(InkCanvas.LeftProperty, newX);
                        this._view.Width -= newX - this._currentPositionX;
                        this._currentPositionX = newX;
                    }
                    if (this._view.ActualHeight - (newY - this._currentPositionY) > minHeight &&
                        newY > 0)
                    {
                        this._view.SetValue(InkCanvas.TopProperty, newY);
                        this._view.Height -= newY - this._currentPositionY;
                        this._currentPositionY = newY;
                    }
                }
                else
                {
                    // 상하좌우 사이즈 변경
                    if (this._view.ActualWidth + newX - this._currentPositionX > 34 &&
                        newX < maxWidth)
                    {
                        this._view.Width += newX - this._currentPositionX;
                        this._currentPositionX = newX;
                    }
                    if (this._view.ActualHeight + newY - this._currentPositionY > minHeight &&
                        newY < maxHeight)
                    {
                        this._view.Height += newY - this._currentPositionY;
                        this._currentPositionY = newY;
                    }
                }

                parentCanvas.UpdateLayout();
            }
        }

        private void ResizeBorder_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
        {
            // 캡쳐 종료, 리사이징 종료
            if (this._isTextBoxResizing == true)
            {
                this._isTextBoxResizing = false;
                Border resizingBorder = sender as Border;
                resizingBorder.ReleaseMouseCapture();
                Util.Log(this, "Resizing complete");
            }
        }

        private void ResizeBorder_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (ModeSetting.GetInstance().DrawMode != DrawingMode.TextMode)
            {
                return;
            }

            // 리사이징 시작, 마우스 캡쳐
            this._isTextBoxResizing = true;

            Border resizingBorder = sender as Border;
            this._selectedResizingBorder = resizingBorder;
            resizingBorder.CaptureMouse();
            this._view = TryFindParent<UserControl>(resizingBorder) as WSPTextBox;
            InkCanvas parentCanvas = TryFindParent<InkCanvas>(this._view);
            this._currentPositionX = e.GetPosition(parentCanvas).X;
            this._currentPositionY = e.GetPosition(parentCanvas).Y;
            Util.Log(this, "Start resizing");
        }

        private List<Border> _lstResizeBorder;
        public List<Border> GetResizeBorderList()
        {
            if (_lstResizeBorder == null)
            {
                _lstResizeBorder = new List<Border>();
                this._lstResizeBorder.Add(this._view.ResizeBorder2);
                this._lstResizeBorder.Add(this._view.ResizeBorder3);
                this._lstResizeBorder.Add(this._view.ResizeBorder4);
                this._lstResizeBorder.Add(this._view.ResizeBorder6);
                this._lstResizeBorder.Add(this._view.ResizeBorder8);
                this._lstResizeBorder.Add(this._view.ResizeBorder9);
                this._lstResizeBorder.Add(this._view.ResizeBorder10);
                this._lstResizeBorder.Add(this._view.ResizeBorder12);
            }
            return this._lstResizeBorder;
        }

        /// <summary>
        /// T와 같은 Typy의 parent를 찾습니다.
        /// </summary>
        /// <typeparam name="T">찾을 parent의 타입</typeparam>
        /// <param name="child">부모를 찾을 child</param>
        /// <returns>T와 같은 타입의 부모를 찾았으면 해당 부모의 객체, 찾지 못했을 경우 null</returns>
        private T TryFindParent<T>(DependencyObject child) where T : DependencyObject
        {
            DependencyObject parentObject = VisualTreeHelper.GetParent(child);
            if (parentObject == null)
            {
                return null;
            }

            T parent = parentObject as T;

            if (parent != null)
            {
                return parent;
            }
            else
            {
                return TryFindParent<T>(parentObject);
            }
        }
    }
}
